package server.connector.http;

import java.io.IOException;
import java.io.InputStream;
/*
用于封装从Socket获取到的输入流,用来解析请求行和请求头
 */

/*
2023/1/17 该类内容全部写完,后续直接使用,无需修改
by cyl
 */
class SocketInputStream extends InputStream {
    //输入流
    private InputStream is;
    //缓冲区
    private byte[] buffer = null;
    //下一个要读数据的下标
    private int pos = 0;
    //实际有效数据长度
    private int length = 0;

    public SocketInputStream(InputStream is, int size) {
        this.is = is;
        buffer = new byte[size];
    }

    @Override
    public int read() throws IOException {
        //如果缓冲区数据读完，重新从输入流读数据到缓冲区
        if (pos >= length) {
            fill();
            if (length <= 0)
                return -1;
        }
        return buffer[pos++] & 0xff;
    }

    @Override
    public void close() throws IOException {
        if (is == null)
            return;
        is.close();
        is = null;
        buffer = null;
    }

    @Override
    public int available() throws IOException {
        return is.available() + (length - pos);
    }

    //重新填充缓冲区
    private void fill() throws IOException {
        length = 0;
        pos = 0;
        length = is.read(buffer);
    }
    private boolean isHttp09 = false;
    //解析请求行
    public void readRequestLine(HttpRequestLine requestLine) throws IOException {
        //复用,避免重复创建对象,减少垃圾回收
        if (requestLine.methodLength != 0)
            requestLine.reuse();
        //跳过空行
        skipBlankLine();
        //读请求方法
        readMethod(requestLine);
        //读uri
        readUri(requestLine);
        //http0.9没有协议号
        if (isHttp09)
            return;
        //读协议版本
        readProtocol(requestLine);
        isHttp09 = false;
    }
    //跳过空行
    private void skipBlankLine() throws IOException {
        int c;
        do {
            c = read();
            if (c == -1)
                throw new IOException("无法读取请求行");
        } while (c == '\r' || c == '\n');
        pos--;
    }

    //读请求方法
    private void readMethod(HttpRequestLine requestLine) throws IOException{
        int maxLength = requestLine.method.length;
        int readCount = 0;
        while (true) {
            int c = read();
            //读到空格 解析请求方法结束
            if (c == ' ') {
                requestLine.methodLength = readCount;
                return;
            } else if (c == -1) {
                throw new IOException("无法读取请求行");
            }
            //如果当前requestLine的method数组存不下数据，扩展
            if (readCount >= maxLength) {
                if (maxLength * 2 <= HttpRequestLine.MAX_METHOD_SIZE) {
                    maxLength = maxLength * 2;
                    char[] newMethod = new char[maxLength];
                    System.arraycopy(requestLine.method, 0, newMethod, 0, requestLine.method.length);
                    requestLine.method = newMethod;
                } else {
                    throw new IOException("请求行太长");
                }
            }
            //读取数据
            requestLine.method[readCount++] = (char)c;

        }
    }
    //读uri
    private void readUri(HttpRequestLine requestLine) throws IOException {
        int maxLength = requestLine.uri.length;
        int readCount = 0;
        while (true) {
            int c = read();
            //读到空格 解析uri结束
            if (c == ' ') {
                requestLine.uriLength = readCount;
                return;
            } else if (c == '\r' || c == '\n') {
                //http0.9风格
                requestLine.uriLength = readCount;
                isHttp09 = true;
            } else if (c == -1) {
                throw new IOException("无法读取请求行");
            }
            //如果当前requestLine的uri数组存不下数据，扩展
            if (readCount >= maxLength) {
                if (maxLength * 2 <= HttpRequestLine.MAX_URI_SIZE) {
                    maxLength = maxLength * 2;
                    char[] newUri = new char[maxLength];
                    System.arraycopy(requestLine.uri, 0, newUri, 0, requestLine.uri.length);
                    requestLine.uri = newUri;
                } else {
                    throw new IOException("请求行太长");
                }
            }
            //读取数据
            requestLine.uri[readCount++] = (char)c;
        }
    }
    //读协议版本
    private void readProtocol(HttpRequestLine requestLine) throws IOException {
        int maxLength = requestLine.protocol.length;
        int readCount = 0;
        while (true) {
            int c = read();
            //读到空格 解析uri结束
            if (c == '\r') {
                continue;
            } else if (c == '\n') {
                requestLine.protocolLength = readCount;
                return;
            }  else if (c == -1) {
                throw new IOException("无法读取请求行");
            }
            //如果当前requestLine的protocol数组存不下数据，扩展
            if (readCount >= maxLength) {
                if (maxLength * 2 <= HttpRequestLine.MAX_PROTOCOL_SIZE) {
                    maxLength = maxLength * 2;
                    char[] newProtocol = new char[maxLength];
                    System.arraycopy(requestLine.protocol, 0, newProtocol, 0, requestLine.protocol.length);
                    requestLine.protocol = newProtocol;
                } else {
                    throw new IOException("请求行太长");
                }
            }
            //读取数据
            requestLine.protocol[readCount++] = (char)c;
        }
    }

    //读一个请求头到header中
    //如果请求头读完，header的nameLength和valueLength都是0
    public void readHeader(HttpHeader header) throws IOException {
        //如果header中存过数据，则复位清空
        if (header.nameLength != 0) {
            header.reuse();
        }
        //检查空行 读到空行说明头部已将读完
        int c = read();
        if (c == '\r' || c == '\n') {
            if (c == '\r') {
                read(); //跳过\n
            }
            header.nameLength = 0;
            header.valueLength = 0;
            return;
        } else {
            pos--;
        }
        //读name
        readName(header);
        readValue(header);

    }
    //读name name大写会转小写
    private void readName(HttpHeader header) throws IOException {
        int maxLength = header.name.length;
        int readCount = 0;
        while (true) {
            int c = read();
            //读到: 结束解析name
            if (c == ':') {
                header.nameLength = readCount;
                break;
            } else if (c == -1) {
                throw new IOException("无法读取请求行");
            }
            //如果当前header的name数组存不下数据，扩展
            if (readCount >= maxLength) {
                if (maxLength * 2 <= HttpHeader.MAX_NAME_SIZE) {
                    maxLength = maxLength * 2;
                    char[] newName = new char[maxLength];
                    System.arraycopy(header.name, 0, newName, 0, header.name.length);
                    header.name = newName;
                } else {
                    throw new IOException("请求行太长");
                }
            }
            //大写转小写
            if (c >= 'A' && c <= 'Z') {
                c = c - ('A' - 'a');
            }
            //读取数据
            header.name[readCount++] = (char)c;
        }
    }
    //读value
    private void readValue(HttpHeader header) throws IOException {
        int maxLength = header.value.length;
        int readCount = 0;
        //跳过空格
        while (true) {
            int c = read();
            if (c == -1) {
                throw new IOException("无法读取请求行");
            } else if (c == ' ' || c == '\t') {

            } else {
                pos--;
                break;
            }
        }
        //开始读value
        while (true) {
            //读到\r\n 结束解析value
            int c = read();
            if (c == '\r') {
                continue;
            } else if (c == '\n') {
                    header.valueLength = readCount;
                    return;
            } else if (c == -1) {
                throw new IOException("无法读取请求行");
            }
            if (readCount >= maxLength) {
                if (maxLength * 2 <= HttpHeader.MAX_VALUE_SIZE) {
                    maxLength = maxLength * 2;
                    char[] newValue = new char[maxLength];
                    System.arraycopy(header.value, 0, newValue, 0, header.value.length);
                    header.value = newValue;
                } else {
                    throw new IOException("请求行太长");
                }
            }
            //读取数据
            header.value[readCount++] = (char)c;
        }
    }
}

